package tree;

import geom.Geom;
import geom.PolarVector;
import geom.Vector;

import java.util.ArrayList;
import java.util.Iterator;

import processing.core.PApplet;


public abstract class TreeNode {
	static int currentId = 0;
	int id;
	int age;
	
	GrowthSequenceGene growthSequence;
	int sequencePos;
	private PolarVector length;
	float weight;
	
	TreeNode parent;
	ArrayList<TreeNode> branches;
	Vector parentPos;
	
	//float startArea;
	private Vector tempPos = null;
	public TreeNode(){
		init();
	}
	public TreeNode(TreeNode b){
		this(b.parent, b.parentPos, b.getLength(), b.getWeight());
	}
	public TreeNode(TreeNode parent, Vector parentPos, PolarVector length, float weight){
		set(parent, parentPos, length, weight);
		init();
	}
	
	public void init(){
			branches = new ArrayList<TreeNode>();
			currentId++;
			id = currentId;
			age = 0;
	}
	
	public void set(TreeNode parent, Vector parentPos, PolarVector length, float weight){
		this.parent = parent;
		this.weight = weight;
		this.length = length;
		this.parentPos = parentPos;
	}
	
	public void set(TreeNode b){
		set(b.parent, b.parentPos, b.getLength(), b.getWeight());
		this.age = b.age;
		this.branches = b.branches;
	}
	
	public TreeNode duplicate(){
		TreeNode b = null;
		try {
			b = this.getClass().newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		b.set(this);
		return b;

	}
	

	public abstract void absorb(float energy);
	public abstract void grow();
	
	public PolarVector getLength(){
		return length;
	}
	public PolarVector getVector(){
		return getLength();
	}
	public float getDist(){
		return getLength().d;
	}
	public float getA(){
		return getLength().a;
	}
	public float getE(){
		return getLength().e;
	}

	
	public void setVector(PolarVector pv){
		length = pv;
		clearCachedPosition();
	}
	public void setDist(float f){
		length.d = f;
		clearCachedPosition();
	}
	public void setA(float f){
		length.a = f;
		clearCachedPosition();
		}
	public void setE(float f){
		length.e = f;
		clearCachedPosition();
	}
	public void addDist(float f){
		length.d += f;
		clearCachedPosition();
	}
	public void addA(float f){
		length.a += f;
		clearCachedPosition();
		}
	public void addE(float f){
		length.e += f;
		clearCachedPosition();
	}

	public void clearCachedPosition(){
		if(this.tempPos == null) return;
		this.tempPos = null;
		Iterator<TreeNode> bit = this.branchIter();
		if(bit == null) return;
		while(bit.hasNext()) bit.next().clearCachedPosition();
	}

	public float getWeight(){
		return weight;
	}
	
	public void getWeightFor(TreeNode child){
		if(branches.contains(child)){
			
		}
	}
	
	public float length(){
		return length.d;
	}
	
	public TreeNode getRoot(){
		if(parent == null) return this;
		return parent.getRoot();
	}

	public abstract float volume();
	
	public float branchVolume(){
		float volume = volume();
		Iterator<TreeNode> bit = branches.iterator();
		while(bit.hasNext()){
			volume += bit.next().branchVolume();
		}
		return volume;
	}
	
	Iterator<TreeNode> iterator;
	public void initBranchIterator(){
		iterator = branches.iterator();
	}
	public Iterator<TreeNode> branchIter(){
		return iterator;
	}
	
	
	public float rootLength(){
		if(parent == null) return length();
		return parent.rootLength();
	}
	
	public float totalVolume(){
		return getRoot().branchVolume();
	}
	public float rootVolume(){
		float volume = volume();
		if(parent == null) return volume;
		return volume + parent.rootVolume();
	}
	public Vector position(){
		if(this.tempPos != null) return tempPos;
		if(parent == null) tempPos =  new Vector();
		else tempPos = parent.position(this);
		return tempPos;
	}
	
	public abstract Vector position(TreeNode b);


}
